package com.zhanghu.backendZray.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zhanghu.backendZray.converter.MenuConverter;
import com.zhanghu.backendZray.exception.ApiException;
import com.zhanghu.backendZray.pojo.dto.MenuDTO;
import com.zhanghu.backendZray.pojo.entity.Menu;
import com.zhanghu.backendZray.mapper.MenuMapper;
import com.zhanghu.backendZray.pojo.request.menu.MenuRequest;
import com.zhanghu.backendZray.pojo.vo.MenuVo;
import com.zhanghu.backendZray.service.MenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.management.MemoryUsage;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zhangdong
 * @since 2024-07-20
 */
@Service
@RequiredArgsConstructor
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
    private final MenuConverter menuConverter;

    /**
     * 获取用户菜单
     *
     * @param userId
     * @return
     */
    @Override
    public List<MenuDTO> getMenusByUserId(Integer userId) {
        List<Menu> menuList = baseMapper.getMenusByUserId(userId);
        return menuList.stream().map(MenuDTO::new).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(MenuRequest menuRequest) {
        Menu menu = menuConverter.input2Entity(menuRequest);
        menu.setId(null);
        Integer parentId = menuRequest.getParentId();
        LambdaUpdateWrapper<Menu> updateWrapper = new UpdateWrapper<Menu>().lambda()
                .eq(Menu::getId, parentId)
                .eq(Menu::getLeaf, true)
                .set(Menu::getLeaf, false);
        this.update(updateWrapper);
        menu.setLeaf(true);
        baseMapper.insert(menu);
    }

    @Override
    public void update(MenuRequest menuRequest) {
        Menu menu = new Menu();
        BeanUtil.copyProperties(menuRequest, menu);
        baseMapper.updateById(menu);
    }

    @Override
    public List<MenuVo> listAllTree() {
        List<Menu> list = list();
        List<MenuVo> menuVos = menuConverter.entity2Vos(list);
        Map<Integer, MenuVo> idMap = menuVos.stream().collect(Collectors.toMap(MenuVo::getId, Function.identity()));
        for (MenuVo vo : menuVos) {
            Integer parentId = vo.getParentId();
            if (parentId != 0) {
                MenuVo parentMenu = idMap.get(parentId);
                parentMenu.getChildren().add(vo);
            }
        }
        menuVos = menuVos.stream().filter(menuVo -> menuVo.getParentId() == 0).collect(Collectors.toList());
        return menuVos;
    }

    @Override
    public List<MenuVo> listAll() {
        List<Menu> list = list();
        return menuConverter.entity2Vos(list);
    }

    /**
     * 前端传过来的是最底层的子菜单id，需要返回所有，包含父菜单id
     * @param menuIdList
     * @return
     */
    @Override
    public List<Integer> listAllMenuIdBYChildIdList(List<Integer> menuIdList) {
        if (CollUtil.isEmpty(menuIdList)) {
            return CollUtil.newArrayList();
        }
        List<Menu> list = list();
        Map<Integer, Menu> idMap = list.stream().collect(Collectors.toMap(Menu::getId, Function.identity()));
        List<Integer> menuIdResultList = CollUtil.newArrayList();
        for (Integer menuId : menuIdList) {
            Menu menu = idMap.get(menuId);
            Integer parentId = menu.getParentId();
            while (parentId != 0) {
                Menu parent = idMap.get(parentId);
                menuIdResultList.add(parent.getId());
                parentId = parent.getParentId();
            }
        }
        menuIdResultList.addAll(menuIdList);
        menuIdResultList = menuIdResultList.stream().distinct().sorted().collect(Collectors.toList());
        return menuIdResultList;
    }
}
